﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using ESpace;
using System.Windows.Forms;

namespace ESpace_Project
{
    public partial class FormEMathF : Form
    {
        Graphics grLine;
        Graphics grRect;
        Graphics grPoly;
        Graphics grLinr;
        Graphics grPlan;
        List<Point> pPlan = new List<Point>();
        Point p = new Point(100, 100);
        Point[] pLine = new Point[4];
        int pLn = 0;
        Point[] pLinr = new Point[2];
        int pLnr = 0;
        List<Point> pPoly = new List<Point>();
        Point PointPoly = new Point(0, 0);
         
        int step = 10;
            int w;
            int h;
            int[,] fld;
            
        //Rectangle rect1 = new Rectangle(100, 50, 50, 50);
        //Rectangle rect2 = new Rectangle(50, 100, 50, 50);
        
        public FormEMathF()
        {
            InitializeComponent();

            imLine.Image = new Bitmap(imLine.Width, imLine.Height);
            grLine = Graphics.FromImage(imLine.Image);

            imRect.Image = new Bitmap(imRect.Width, imRect.Height);
            grRect = Graphics.FromImage(imRect.Image);

            imPoly.Image = new Bitmap(imPoly.Width, imPoly.Height);
            grPoly = Graphics.FromImage(imPoly.Image);

            imLinr.Image = new Bitmap(imLinr.Width, imLinr.Height);
            grLinr = Graphics.FromImage(imLinr.Image);

            imPlan.Image = new Bitmap(imPlan.Width, imPlan.Height);
            grPlan = Graphics.FromImage(imPlan.Image);

        }


        private void timer1_Tick(object sender, EventArgs e)
        {
            Random rnd = new Random();
            Point[] tmpPts = new Point[pPoly.Count];
                    for (int i = 0; i < pPoly.Count; i++)
                    {
                        tmpPts[i] = pPoly[i];
                    }
            for (int i = 0; i < 1000; i++)
            {
                int x = rnd.Next(imPoly.Width);
                int y = rnd.Next(imPoly.Height);
                bool bDraw =  bDraw = EMath.PointInPoly(tmpPts, new Point(x, y));
              
                if (bDraw)
                    grPoly.FillRectangle(Brushes.Red, x, y, 1, 1);
            }
            imPoly.Refresh();
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            /*grLine.FillRectangle(Brushes.Transparent, 0, 0, imLine.Width, imLine.Height);
            grRect.FillRectangle(Brushes.Transparent, 0, 0, imRect.Width, imRect.Height);
            grPoly.FillRectangle(Brushes.Transparent, 0, 0, imPoly.Width, imPoly.Height);*/
            tmrPoly.Enabled = false;
            if (tabControl1.SelectedIndex == 3)
            {
                DrawLinr();   
            }
        }

        private void imLine_MouseClick(object sender, MouseEventArgs e)
        {
            pLine[pLn].X = e.X;
            pLine[pLn].Y = e.Y;
            pLn++;
            // рисуем
            DrawLine();
        }

        private void DrawLine()
        {
            listBox1.Items.Clear();
            grLine.Clear(Color.FromArgb(224, 224, 224));
            
            for (int i = 0; i < pLn; i++)
                grLine.FillRectangle(Brushes.Black, pLine[i].X, pLine[i].Y, 1, 1);
            if (pLn > 1)
                grLine.DrawLine(Pens.Black, pLine[0], pLine[1]);
            if (pLn > 3)
            {
                grLine.DrawLine(Pens.Red, pLine[2], pLine[3]);
                bool tmpb = EMath.CrossingLines(pLine[0], pLine[1], pLine[2], pLine[3]);
                listBox1.Items.Add("CrossingLines = " + tmpb.ToString());
                tmpb = EMath.CrossingLines1(pLine[0], pLine[1], pLine[2], pLine[3]);
                listBox1.Items.Add("CrossingLines1 = " + tmpb.ToString());
                pLn = 0;
            }
            imLine.Refresh();
        }

        private void imPoly_MouseClick(object sender, MouseEventArgs e)
        {

            bool tmpDrawPoint = false;
            // если полигон есть и он завершен, ставим точку и считаем
            if (pPoly.Count > 0 & btnDrawPoly.Enabled)
            {
                listBox1.Items.Clear();
                
                Point[] tmpPts = new Point[pPoly.Count];
                for (int i = 0; i < pPoly.Count; i++)
                {
                    tmpPts[i] = pPoly[i];
                }
                Point tmpP = new Point(e.X, e.Y);
                PointPoly = tmpP;
                bool tmpb = EMath.PointInPoly(tmpPts, tmpP);
                listBox1.Items.Add("InPoly = " + tmpb.ToString());
                
                tmpDrawPoint = true;
            }
         
            // если многоугольник состоит минимум из 3 точек и следующая точка близка к первой точке, закрываем многоугольник
            if (pPoly.Count > 2)
                if(Math.Abs(e.X - pPoly[0].X) < 5 & Math.Abs(e.Y - pPoly[0].Y) < 5) btnDrawPoly.Enabled = true;

            // если рeжим рисования многоугольника, добавляем точку
            if (btnDrawPoly.Enabled == false)
            {
                pPoly.Add(new Point(e.X, e.Y));
            }

            // рисуем
            grPoly.Clear(Color.FromArgb(224, 224, 224));
            if (pPoly.Count > 0)
            {
                // если только 1 точка, рисуем точку
                if (pPoly.Count == 1)
                    grPoly.DrawRectangle(Pens.Black, pPoly[0].X, pPoly[0].Y, 1, 1);
                // если полигон завершен, рисуем полигон
                if (btnDrawPoly.Enabled)
                {
                    DrawPoligon();
                    if (tmpDrawPoint)
                    {
                        grPoly.FillRectangle(Brushes.Red, e.X, e.Y, 1, 1);
                        grPoly.DrawEllipse(Pens.Black, e.X - 3, e.Y - 3, 6, 6);
                    }
                }
                else
                    // пробегаемся по всем точкам и рисуем линии
                    for (int i = 0; i < pPoly.Count - 1; i++)
                    {
                        grPoly.DrawLine(Pens.Black, pPoly[i], pPoly[i + 1]);
                    }  
            }
            
            imPoly.Refresh();

        }

        void DrawPoligon()
        {
            Point[] tmpPts = new Point[pPoly.Count];
            for (int i = 0; i < pPoly.Count; i++)
            {
                tmpPts[i] = pPoly[i];
            }
            grPoly.FillPolygon(Brushes.Snow, tmpPts);
        }

        private void btnDrawPoly_Click(object sender, EventArgs e)
        {
            btnDrawPoly.Enabled = false;
            pPoly.Clear();
        }

        private void btnFillPoly_Click(object sender, EventArgs e)
        {
            tmrPoly.Enabled = !tmrPoly.Enabled;
        }

        private void imLinr_MouseClick(object sender, MouseEventArgs e)
        {
            pLinr[pLnr].X = e.X;
            pLinr[pLnr].Y = e.Y;
            pLnr++;
            
            // рисуем
            DrawLinr();
        }
        private void DrawLinr()
        {
            // рисуем
            listBox1.Items.Clear();
            grLinr.Clear(Color.FromArgb(224, 224, 224));
            // рисуем квадрат
            Rectangle r = new Rectangle(100, 100, 50, 50);
            grLinr.DrawRectangle(Pens.Black, r);
            // рисуем точку
            if (pLnr == 1)
                grLinr.FillRectangle(Brushes.Black, pLinr[0].X, pLinr[0].Y, 1, 1);
            // рисуем линию и считаем
            if (pLnr > 1)
            {
                grLinr.DrawLine(Pens.Black, pLinr[0], pLinr[1]);
                bool tmpb = EMath.LineCrossRect(r, pLinr[0], pLinr[1]);
                listBox1.Items.Add("LineInRect = " + tmpb.ToString());
                pLnr = 0;
            }
            imLinr.Refresh();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int x1 = 0, x2 = 0, x3 = 0, x4 = 0, y1 = 0, y2 = 0, y3 = 0, y4 = 0;
            int.TryParse(txbP1X.Text, out x1);
            pLine[0].X = x1;
            int.TryParse(txbP1Y.Text, out y1);
            pLine[0].Y = y1;
            int.TryParse(txbP2X.Text, out x2);
            pLine[1].X = x2;
            int.TryParse(txbP2Y.Text, out y2);
            pLine[1].Y = y2;
            int.TryParse(txbP3X.Text, out x3);
            pLine[2].X = x3;
            int.TryParse(txbP3Y.Text, out y3);
            pLine[2].Y = y3;
            int.TryParse(txbP4X.Text, out x4);
            pLine[3].X = x4;
            int.TryParse(txbP4Y.Text, out y4);
            pLine[3].Y = y4;
            pLn = 4;
            DrawLine();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            btnDrawPlanPoly.Enabled = false;
            pPlan.Clear();
            w = imPlan.Width / step;
            h = imPlan.Height / step;
            fld = new int[w, h];

            for (int i = 0; i < w; i++)
                for (int j = 0; j < h; j++)
                    fld[i, j] = 0;
            DrawPlan();
        }

        private void imPlan_MouseClick(object sender, MouseEventArgs e)
        {

            // если многоугольник состоит минимум из 3 точек и следующая точка близка к первой точке, закрываем многоугольник
            if (pPlan.Count > 2)
                if (Math.Abs(e.X - pPlan[0].X) < 5 & Math.Abs(e.Y - pPlan[0].Y) < 5) btnDrawPlanPoly.Enabled = true;

            // если рeжим рисования многоугольника, добавляем точку
            if (btnDrawPlanPoly.Enabled == false)
            {
                pPlan.Add(new Point(e.X, e.Y));
            }

            // если полигон есть и он завершен, считаем
            if (pPlan.Count > 0 & btnDrawPlanPoly.Enabled)
            {
                CalcPlan();
            }
            DrawPlan();
        }

        private void CalcPlan()
        {
            // если полигон есть и он завершен, считаем
            if (pPlan.Count > 0 & btnDrawPlanPoly.Enabled)
            {
                // находим минамальную и максимальную точку
                Point minP = new Point(int.MaxValue, int.MaxValue);
                Point maxP = new Point(int.MinValue, int.MinValue);

                Point[] tmpPts = new Point[pPlan.Count];
                for (int i = 0; i < pPlan.Count; i++)
                {
                    tmpPts[i] = pPlan[i];
                }

                for (int i = 0; i < pPlan.Count; i++)
                {
                    if (minP.X > pPlan[i].X) minP.X = pPlan[i].X;
                    if (minP.Y > pPlan[i].Y) minP.Y = pPlan[i].Y;
                    if (maxP.X < pPlan[i].X) maxP.X = pPlan[i].X;
                    if (maxP.Y < pPlan[i].Y) maxP.Y = pPlan[i].Y;
                }
                for (int i = minP.X / step; i < maxP.X / step + 1; i++)
                    for (int j = minP.Y / step; j < maxP.Y / step + 1; j++)
                    {
                        if (EMath.PolyCrossRect(tmpPts, new Rectangle(i * step, j * step, step, step)))
                            fld[i, j] = 1;
                    }
            }
        }

        private void CalcPlan1()
        {
            // если полигон есть и он завершен, считаем
            if (pPlan.Count > 0 & btnDrawPlanPoly.Enabled)
            {
                // находим минамальную и максимальную точку
                Point minP = new Point(int.MaxValue, int.MaxValue);
                Point maxP = new Point(int.MinValue, int.MinValue);

                Point[] tmpPts = new Point[pPlan.Count];
                for (int i = 0; i < pPlan.Count; i++)
                {
                    tmpPts[i] = pPlan[i];
                }

                for (int i = 0; i < pPlan.Count; i++)
                {
                    if (minP.X > pPlan[i].X) minP.X = pPlan[i].X;
                    if (minP.Y > pPlan[i].Y) minP.Y = pPlan[i].Y;
                    if (maxP.X < pPlan[i].X) maxP.X = pPlan[i].X;
                    if (maxP.Y < pPlan[i].Y) maxP.Y = pPlan[i].Y;
                }
                for (int i = minP.X / step; i < maxP.X / step + 1; i++)
                    for (int j = minP.Y / step; j < maxP.Y / step + 1; j++)
                    {
                        if (EMath.PolyCrossRect1(tmpPts, new Rectangle(i * step, j * step, step, step)))
                            fld[i, j] = 1;
                    }
            }
        }
        
        private void DrawPlan()
        {
            // рисуем
            grPlan.Clear(Color.FromArgb(224, 224, 224));

            for(int i= 0; i< w;i++)
                    for (int j = 0; j < h; j++)
                    {
                        if (fld[i, j] != 0) grPlan.FillRectangle(Brushes.Gray, i * step, j * step, step, step);
                        grPlan.DrawRectangle(Pens.Black, i * step, j * step, step, step);
                        
                    }

            if (pPlan.Count > 0)
            {
                // если только 1 точка, рисуем точку
                if (pPlan.Count == 1)
                    grPlan.DrawRectangle(Pens.Black, pPlan[0].X, pPlan[0].Y, 1, 1);
                // если полигон завершен, рисуем полигон
                if (btnDrawPlanPoly.Enabled)
                {
                    Point[] tmpPts = new Point[pPlan.Count];
                    for (int i = 0; i < pPlan.Count; i++)
                    {
                        tmpPts[i] = pPlan[i];
                    }
                    //grPlan.FillPolygon(Brushes.Snow, tmpPts);
                    grPlan.DrawPolygon(Pens.Snow, tmpPts);
                }
                else
                    // пробегаемся по всем точкам и рисуем линии
                    for (int i = 0; i < pPlan.Count - 1; i++)
                    {
                        grPlan.DrawLine(Pens.Black, pPlan[i], pPlan[i + 1]);
                    }
            }

            imPlan.Refresh();
        }

        private void btnPlanTime_Click(object sender, EventArgs e)
        {
            DateTime t = DateTime.Now;
            const int delay = 1000;
            listBox1.Items.Clear();
            for (int i = 0; i < delay; i++)
            {
                CalcPlan();
                //DrawPlan();
            }
            TimeSpan ts = new TimeSpan(DateTime.Now.Ticks - t.Ticks);
            listBox1.Items.Add(ts.TotalMilliseconds.ToString());

            t = DateTime.Now;
            for (int i = 0; i < delay; i++)
            {
                CalcPlan1();
                //DrawPlan();
            }
            ts = new TimeSpan(DateTime.Now.Ticks - t.Ticks);
            listBox1.Items.Add(ts.TotalMilliseconds.ToString());

            
        }


        Point pntRect1 = new Point(-1, -1);
        Point pntRect2 = new Point(-1, -1);
        Point pnt1 = new Point(-1, -1);
        Point pnt2 = new Point(-1, -1);
        private void imRect_MouseDown(object sender, MouseEventArgs e)
        {
            if (pntRect1.X == -1) pntRect1 = e.Location;
            else if (pntRect2.X == -1) pntRect2 = e.Location;
            else if (pnt1.X == -1) pnt1 = e.Location;
            else
            {
                if (rbxRect2.Checked)
                {
                    if (pnt2.X == -1) pnt2 = e.Location;
                    else { pnt1 = e.Location; pnt2 = new Point(-1, -1); }
                }
                else pnt1 = e.Location;
            }

            ReDrawImRect();
        }

        void ReDrawImRect()
        {
            listBox1.Items.Clear();
            grRect.Clear(Color.Wheat);
            while (true)
            {
                if (pntRect1.X == -1) break;
                grRect.FillRectangle(Brushes.Black, pntRect1.X, pntRect1.Y, 1, 1);
                if (pntRect2.X == -1) break;

                int x = pntRect1.X;
                int y = pntRect1.Y;
                int w = pntRect2.X - pntRect1.X;
                int h = pntRect2.Y - pntRect1.Y;
                if (w < 0) { x = pntRect2.X; w *= -1; }
                if (h < 0) { y = pntRect2.Y; h *= -1; }
                Rectangle rect = new Rectangle(x, y, w, h);
                grRect.DrawRectangle(Pens.Black, rect);

                if (pnt1.X == -1) break;

                grRect.FillRectangle(Brushes.Red, pnt1.X, pnt1.Y, 1, 1);

                if (rbxRect1.Checked)
                {
                    listBox1.Items.Add(EMath.PointInRect(rect, pnt1).ToString());
                }
                else
                {
                    if (pnt2.X == -1) break; 

                    x = pnt1.X;
                    y = pnt1.Y;
                    w = pnt2.X - pnt1.X;
                    h = pnt2.Y - pnt1.Y;
                    if (w < 0) { x = pnt2.X; w *= -1; }
                    if (h < 0) { y = pnt2.Y; h *= -1; }
                    Rectangle rect1 = new Rectangle(x, y, w, h);

                    grRect.DrawRectangle(Pens.Red, rect1);

                    listBox1.Items.Add(EMath.CrossRect(rect, rect1).ToString());
                }

                break;
            }
            imRect.Refresh();
        }

        private void btnRectClear_Click(object sender, EventArgs e)
        {
            pntRect1 = new Point(-1, -1);
            pntRect2 = new Point(-1, -1);
            pnt1 = new Point(-1, -1);
            pnt2 = new Point(-1, -1);
            ReDrawImRect();
        }

       
    }
}
